/**
 * Copyright (c) 2011-2012 Tomi Paananen.
 *
 * Part of Quick Gestures engine library.
 */

// Own header
#include "quickgesturesengine.h"

// qgengine includes
#include "classifierthread.h"
#include "gesturemodel.h"
#include "storagethread.h"
#include "qgtrace.h"


/*!
  \class QuickGesturesEngine
  \brief The engine interface.
*/


/*!
  Constructor.
*/
QuickGesturesEngine::QuickGesturesEngine(QObject *parent /* = 0 */)
    : QObject(parent),
      m_classifierThread(0),
      m_storageThread(0),
      m_gestureModel(0),
      m_tempGesture(0),
      m_state(Idle)
{
    m_storageThread = new StorageThread(this);
    m_gestureModel = new GestureModel(this);

    connect(m_storageThread, SIGNAL(gestureLoaded(Gesture*)),
            m_gestureModel, SLOT(addGesture(Gesture*)));

    m_classifierThread = new ClassifierThread(this);

    connect(m_classifierThread, SIGNAL(succeeded(quint32,QString)),
            this, SIGNAL(succeeded(quint32,QString)));
    connect(m_classifierThread, SIGNAL(failed(int)),
            this, SIGNAL(failed(int)));
    connect(m_classifierThread, SIGNAL(succeeded(quint32,QString)),
            this, SLOT(setStateToIdle()));
    connect(m_classifierThread, SIGNAL(failed(int)),
            this, SLOT(setStateToIdle()));
    connect(m_classifierThread, SIGNAL(cancelled()),
            this, SLOT(cancellationConfirmed()));
    connect(m_classifierThread, SIGNAL(progress(int)),
            this, SIGNAL(progress(int)));

    emit storageThreadChanged(m_storageThread);
    emit modelChanged(m_gestureModel);
    DEBUG_POINT;
}


/*!
  Destructor.
*/
QuickGesturesEngine::~QuickGesturesEngine()
{
    m_storageThread->cancel();
    m_classifierThread->cancel();
}


/*!
  Returns the classifier thread.
*/
ClassifierThread *QuickGesturesEngine::classifierThread() const
{
    return m_classifierThread;
}


/*!
  Returns the current state of the engine.
*/
int QuickGesturesEngine::state() const
{
    return (int)m_state;
}


/*!
  Returns the storage thread.
*/
StorageThread *QuickGesturesEngine::storageThread() const
{
    return m_storageThread;
}


/*!
  Returns the gesture model.
*/
GestureModel *QuickGesturesEngine::gestureModel() const
{
    return m_gestureModel;
}


/*!
  Tries to recognize \a gesture. Returns true if the recognition process was
  started, false otherwise.
*/
bool QuickGesturesEngine::recognize(Gesture *gesture)
{
    DEBUG_INFO(gesture);

    if (!gesture || m_classifierThread->state() == ClassifierThread::Running) {
        DEBUG_INFO("Invalid argument or the classifier thread is busy!");
        return false;
    }

    // Make a copy of the given gesture.
    if (m_tempGesture) {
        delete m_tempGesture;
    }

    m_tempGesture = new Gesture(*gesture, this);

    m_classifierThread->setGestureSet(m_gestureModel->gestures());
    m_classifierThread->setGesture(m_tempGesture);
    m_classifierThread->start();
    setState(Recognizing);
    return true;
}


/*!
  Cancels the recognition operation.
*/
void QuickGesturesEngine::cancelRecognition()
{
    if (m_classifierThread->state() == ClassifierThread::Idle) {
        DEBUG_INFO("The classifier thread is not running!");
        setState(Idle);
        return;
    }

    m_classifierThread->cancel();
    setState(Cancelling);
}


/*!
  Clears the gesture model.
*/
void QuickGesturesEngine::clearModel()
{
    m_gestureModel->clear();
}


/*!
  Sets \a state as the state of the engine.
*/
void QuickGesturesEngine::setState(EngineStates state)
{
    m_state = state;
    emit stateChanged((int)state);
}


/*!
  For convenience. Sets the state to Idle.
*/
void QuickGesturesEngine::setStateToIdle()
{
    setState(Idle);
}


/*!
  Gets called when the thread notifies that it has cancelled the operation.
  Notifies observers by emitting cancelled() signal and sets the state to idle.
*/
void QuickGesturesEngine::cancellationConfirmed()
{
    DEBUG_POINT;
    emit cancelled();
    setState(Idle);
}


// End of file.
